<?php

namespace App\Models;

use App\Models\Comment;
use App\Models\Like;
use App\Models\Order;
use App\Models\Score;
use App\Models\Test;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Models\Topic;
use App\Models\AttachmentRelationship;
use App\Models\Attachment;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use Ramsey\Uuid\Uuid;
use App\Models\UserThirdPartyBind;
use ScoutElastic\Searchable;
use App\IndexConfigurators\UserIndexConfigurator;
use App\SearchRules\UserSearchRule;
use Encore\Admin\Models\Administrator;

class User extends Administrator
{
    use HasApiTokens;
    use Notifiable;
//    use Searchable;

    //用户默认敏感能力，很低，1
    const DEFAULT_SENSITIVITY_ABILITY = 1;

    const ROLE_SUPER_ADMIN_NAME = 'super_admin';

//    const DEFAULT_AVATAR = '17z1jmEz303dddjKTeVGVCGFEgAIZB2zwMx6hX67.jpeg';
    const DEFAULT_AVATAR = 'noavatar_middle';

    const REGISTER_SOURCE_EMAIL = 'email';
    const REGISTER_SOURCE_WEIXIN_OPEN = UserThirdPartyBind::PLATFORM_WEIXIN_OPEN;
    const REGISTER_SOURCE_QQ = UserThirdPartyBind::PLATFORM_QQ;

    private static $canSeeTopicHideMap = [];


    protected $indexConfigurator = UserIndexConfigurator::class;

    protected $searchRules = [
        UserSearchRule::class
    ];

    protected $fillable = ['username', 'password', 'name', 'avatar', 'email', 'register_source', ];

    public static function booted()
    {
        static::creating(function ($model) {
            $model->key = Uuid::uuid4();
        });
    }

    /**
     * 为数组 / JSON 序列化准备日期。
     *
     * @param  \DateTimeInterface  $date
     * @return string
     */
    protected function serializeDate(\DateTimeInterface $date)
    {
        return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
    }

    public function getAvatarAttribute($avatar)
    {
        $avatar = $avatar ?: self::DEFAULT_AVATAR;
        return attachmentUrl($avatar);
    }

    public function setAvatarAttribute($value)
    {
       if (Str::startsWith($value, "http")) {
           $urlParts = explode('/', $value);
           $value = end($urlParts);
           if (stripos($value, ".") !== false) {
                $value = strstr($value, ".", true);
           }
       }
       $this->attributes['avatar'] = $value;
    }

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    public function topics()
    {
        return $this->hasMany(Topic::class, 'uid');
    }

    /**
     * 第三方平台绑定
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function thirdPartyBinds()
    {
        return $this->hasMany(UserThirdPartyBind::class, 'uid');
    }


    /**
     * 用户头像，其实是一个附件（图片）
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function avatarAttachment()
    {
        return $this->hasOne(Attachment::class, "key", "avatar")->withDefault(function () {
            return new Attachment([
                'mime_type' => 'image/jpeg',
                'key' => self::DEFAULT_AVATAR,
            ]);
        });
    }
    
    /**
     * 用户全部的头像。target_type = 'user_avatar'
     *
     * @see App\Providers\AppServiceProvider::customMorphMap()
     * @return \Illuminate\Database\Eloquent\Relations\MorphToMany
     */
    public function allAvatarAttachment()
    {
        return $this->morphToMany(
            Attachment::class,
            "target",
            AttachmentRelationship::TABLE_NAME,
            "target_id",
            "attachment_id",
            "id",
            "key"
        );
    }

    public function likes()
    {
        return $this->hasMany(Like::class, 'uid');
    }

    /**
     * 用户点赞过的评论
     */
    public function likeComments()
    {
        return $this->hasManyThrough(Comment::class, Like::class, 'uid', 'id','id', 'target_id')
            ->where('target_type', Comment::class)->withTrashed();
    }

    public function scores()
    {
        return $this->hasMany(Score::class, 'uid');
    }

    /**
     * 用户的回复，包括楼中楼
     * 正常楼层，pid = 0, root_id = 0, floor_num > 1
     * 楼中楼，pid > 0 , root_id > 0, floor_num > 0
     *
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function comments()
    {
        return $this->hasMany(Comment::class, 'uid')->where('is_main_floor', 0)->withTrashed();
    }

    /**
     * 直接回复，不包括楼中楼
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function directComments()
    {
        return $this->comments()->where('pid', 0);
    }

    public function orders()
    {
        return $this->hasMany(Order::class, 'uid');
    }

    public function test()
    {
        return $this->hasOne(Test::class, 'uid');
    }

    /**
     * @param $topic
     * @return array|int|mixed
     */
    public function canSeeTopicHide($topic)
    {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
        $backtrace = $backtrace[0];
        $caller = sprintf(
            '%s %s %s %s %s %s',
            $backtrace['file'], $backtrace['class'], $backtrace['object']['id'],
            $backtrace['type'], $backtrace['function'], json_encode_unicode($backtrace['args'])
        );
        $log = __METHOD__ . ", uid: {$this->id}, caller: $caller";
        if (is_scalar($topic) && isset(self::$canSeeTopicHideMap[$topic])) {
            $result = self::$canSeeTopicHideMap[$topic];
            logger("$log, topic: $topic, already determine, result: " . json_encode_unicode($result));
            return $result;
        }
        if (!$topic instanceof Topic) {
            $topic = Topic::query()->findOrFail($topic);
        }
        $tid = $topic->id;
        $log .= ", tid: $tid";
        if (isset(self::$canSeeTopicHideMap[$tid])) {
            $result = self::$canSeeTopicHideMap[$tid];
            logger("$log, already determine, result: " . json_encode_unicode($result));
            return $result;
        }
        $hide = $topic->mainFloor->hide;
        $hasReply = $this->comments()->where('tid', $topic->id)->count();
        $hasBuyTopic = $this->orders()->goodsTypeIsTopic($topic->id)->paid()->count();
        $hasHide = intval(!is_null($hide));
        $log .= sprintf(', hasReply: %s, hasBuyTopic: %s', $hasReply, $hasBuyTopic);
        if ($this->id == $topic->uid) {
            $result = 1;
            $log .= ", topic uid == current user id, can see";
        } else {
            if ($hasHide) {
                $log .= sprintf(
                    ", hasHide: %s, require_reply: %s,  require_score: %s",
                    $hasHide, $hide->require_reply, $hide->require_score
                );
                if (($hide->require_score && !$hasBuyTopic) || ($hide->require_reply && !$hasReply)) {
                    //保持不变，还是不能看
                    $result = 0;
                    $log .= ", can't see";
                } else {
                    $result = 1;
                    $log .= ", can see";
                }

            } else {
                $result = 0;
                $log .= ", no hide, can't see";
            }
        }

        logger($log);

        $cache = [
            'has_reply' => $hasReply,
            'has_buy' => $hasBuyTopic,
            'result' => $result,
        ];
        return self::$canSeeTopicHideMap[$tid] = $cache;

    }




}
